package org.example.io;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.example.io.handler.ClientLoginHandler;
import org.example.io.handler.PacketDecoder;
import org.example.io.handler.PacketEncoder;
import org.example.io.handler.client.CreateGroupResponsePacketHandler;
import org.example.io.handler.client.LoginResponsePacketHandler;
import org.example.io.handler.client.MessageResponsePacketHandler;
import org.example.io.protocol.command.CommandUtil;
import org.example.io.protocol.command.ConsoleCommand;
import org.example.io.protocol.packet.LoginRequestPacket;
import org.example.io.protocol.packet.MessageRequestPacket;
import org.example.io.protocol.packet.PacketCodec;
import org.example.io.util.LogUtil;
import org.example.io.util.LoginUtil;

import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.Scanner;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
public class NettyClient {

    private static final int MAX_RETRY = 5;

    public static void main(String[] args) {
        // 1、定义线程模型
        Bootstrap bootstrap = new Bootstrap();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        bootstrap.group(worker);

        // 2、配置
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true);

        // 3、IO模型
        bootstrap.channel(NioSocketChannel.class);

        bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel ch) throws Exception {
                ch.pipeline().addLast(new PacketDecoder());
                ch.pipeline().addLast(new LoginResponsePacketHandler());
                ch.pipeline().addLast(new MessageResponsePacketHandler());
                ch.pipeline().addLast(new CreateGroupResponsePacketHandler());
                ch.pipeline().addLast(new PacketEncoder());
            }
        });

        connect(bootstrap, 8000, MAX_RETRY);
    }

    public static void connect(Bootstrap bootstrap, int port, int retry) {
        bootstrap.connect(new InetSocketAddress(port)).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                if (future.isSuccess()) {
                    log.info("客户端连接成功");
                    Channel channel = future.channel();
                    startConsoleThread(channel);
                } else if (retry == 0) {
                    log.info("超过重连次数，客户端关闭");
                } else {
                    // 进行重连
                    // 1、剩余多少次
                    int order = MAX_RETRY - retry + 1;
                    log.info("当前第几次重连：{}", order);
                    int time = 1 << order;
                    bootstrap.config().group().schedule(() -> {
                        connect(bootstrap, port, retry - 1);
                    }, time, TimeUnit.SECONDS);
                }
            }
        });
    }

    public static void startConsoleThread(Channel channel) {
        new Thread(() -> {

            boolean isLogining = false;
            // 判断当前线程有没有中断
            CommandUtil.printCommand();
            while (!Thread.interrupted()) {
                try {
                    // 请输入命令
                    InputStream ins = System.in;
                    Scanner scanner = new Scanner(ins);

                    String commandType = scanner.next();
                    ConsoleCommand command = CommandUtil.getCommand(commandType);
                    if (command == null) {
                        LogUtil.info("无法识别【" + commandType + "】指令，请重新输入");
                    } else {
                        command.exec(scanner, channel);
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }
}
